package cn.zwx.goods.svc.rpc;

import cn.zwx.base.entity.ResponseEntity;
import cn.zwx.base.exception.BizWrapException;
import cn.zwx.base.utils.ValidationUtils;
import cn.zwx.goods.svc.constans.GoodsConstans;
import cn.zwx.goods.svc.domain.CategoryAttrDO;
import cn.zwx.goods.svc.domain.entity.CategoryAttrEntity;
import cn.zwx.goods.svc.domain.entity.CategoryEntity;
import cn.zwx.goods.svc.domain.enums.DelFlag;
import cn.zwx.goods.svc.domain.enums.GoodsCodeEnum;
import cn.zwx.goods.svc.rpc.dto.*;
import cn.zwx.goods.svc.rpc.facade.DubboCategoryService;
import cn.zwx.goods.svc.rpc.vo.*;
import cn.zwx.goods.svc.service.CategoryService;
import cn.zwx.goods.svc.warp.ExceptionWrap;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.apidocs.annotations.ApiDoc;
import org.apache.dubbo.apidocs.annotations.ApiModule;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @author zhangwenxue
 */
@Service
@ApiModule(value = "类目相关接口", apiInterface = DubboCategoryService.class)
@DubboService(version = "v1.0.0",interfaceClass = DubboCategoryService.class,timeout = 8000)
public class DubboCategoryServiceImpl  implements DubboCategoryService {

    @Resource
    private CategoryService categoryService;

    @Override
    @ApiDoc(value = "查询类目列表接口")
    public ResponseEntity<List<CategoryInfoVO>> selectList(CategoryListDTO dto) throws BizWrapException {
        // 1.check request
        ValidationUtils.getInstance().validate(dto);
        // 2.query list
        LambdaQueryWrapper<CategoryEntity> categoryWrapper = new LambdaQueryWrapper<>();
        categoryWrapper.like(StringUtils.isBlank(dto.getName()),CategoryEntity::getName,dto.getName());
        categoryWrapper.eq(ObjectUtils.isEmpty(dto.getParentId()),CategoryEntity::getParentId,dto.getParentId());
        categoryWrapper.eq(CategoryEntity::getDelFlag, DelFlag.normal.getCode());
        categoryWrapper.orderByAsc(CategoryEntity::getSort);
        List<CategoryEntity> categoryList = categoryService.selectList(categoryWrapper);
        // 3.return list
        if (CollectionUtils.isEmpty(categoryList)){
            return ResponseEntity.success(new ArrayList<>());
        }
        List<CategoryInfoVO> returnList = new ArrayList<>();
        categoryList.forEach(t->{
            CategoryInfoVO categoryInfoVO = new CategoryInfoVO();
            categoryInfoVO.setId(t.getId());
            categoryInfoVO.setName(t.getName());
            categoryInfoVO.setSort(t.getSort());
            categoryInfoVO.setParentId(t.getParentId());
            categoryInfoVO.setCreateTime(t.getCreateTime());
            categoryInfoVO.setUpdateTime(t.getUpdateTime());
            returnList.add(categoryInfoVO);
        });
        return ResponseEntity.success(returnList);
    }
    /**
     * 查询类目列表(树结构)接口
     * @param dto 请求参数
     * @return 返回参数
     * @throws BizWrapException 业务异常
     */
    @Override
    @ApiDoc(value = "查询类目列表(树结构)接口")
    public ResponseEntity<List<CategoryTreeVO>> selectTreeList(CategoryListDTO dto) throws BizWrapException {
        // 1.check request
        ValidationUtils.getInstance().validate(dto);
        // 2.select List
        LambdaQueryWrapper<CategoryEntity> categoryWrapper = new LambdaQueryWrapper<>();
        final Integer parentId = dto.getParentId();
        categoryWrapper.eq(CategoryEntity::getParentId,ObjectUtils.isEmpty(parentId)? GoodsConstans.NEGATIVE_INT_1:parentId);
        categoryWrapper.like(StringUtils.isBlank(dto.getName()),CategoryEntity::getName,dto.getName());
        categoryWrapper.orderByAsc(CategoryEntity::getSort);
        categoryWrapper.eq(CategoryEntity::getDelFlag, DelFlag.normal.getCode());
        List<CategoryEntity> selectList = categoryService.selectList(categoryWrapper);
        // 3.return package
        if (CollectionUtils.isEmpty(selectList)){
            return ResponseEntity.success();
        }
        List<CategoryTreeVO> returnList = new ArrayList<>();
        for (CategoryEntity categoryEntity : selectList) {
            final CategoryTreeVO categoryTreeVO = new CategoryTreeVO();
            BeanUtils.copyProperties(categoryEntity,categoryTreeVO);
            deepLoopChildList(categoryTreeVO);
        }
        return ResponseEntity.success(returnList);
    }

    @Override
    @ApiDoc(value = "根据类目id类目信息接口")
    public ResponseEntity<CategoryVO> selectByInfo(CategoryInfoDTO dto) throws BizWrapException {
        // 1.check request
        ValidationUtils.getInstance().validate(dto);
        // 2.query info ...
        CategoryEntity categoryEntity = categoryService.selectById(dto.getId());
        if (ObjectUtils.isEmpty(categoryEntity)){
            throw ExceptionWrap.wrap(GoodsCodeEnum.CATEGORY_INFO_NOT_EXIST_ERROR);
        }
        // 3.deep loop child list
        CategoryVO categoryVO = new CategoryVO();
        categoryVO.setId(categoryEntity.getId());
        categoryVO.setSort(categoryEntity.getSort());
        categoryVO.setName(categoryEntity.getName());
        categoryVO.setParentId(categoryEntity.getParentId());
        categoryVO.setCreateTime(categoryEntity.getCreateTime());
        categoryVO.setUpdateTime(categoryEntity.getUpdateTime());
        // 4.query attr value
        final List<CategoryAttrVO> categoryAttr = this.getCategoryAttr(categoryVO.getId());
        categoryVO.setAttrList(categoryAttr);
        // 5.return obj
        return ResponseEntity.success(categoryVO);
    }

    private List<CategoryAttrVO> getCategoryAttr(Integer categoryId) {
        List<CategoryAttrVO> attrList = new ArrayList<>();
        List<CategoryAttrDO> attrValList = categoryService.selectAttrList(categoryId);
        if (!CollectionUtils.isEmpty(attrValList)){
            attrValList.forEach(t->{
                final CategoryAttrVO categoryAttrVO = new CategoryAttrVO();
                BeanUtils.copyProperties(t,categoryAttrVO);
                attrList.add(categoryAttrVO);
            });
        }
        return attrList;
    }

    private void deepLoopChildList(CategoryTreeVO categoryVO){
        LambdaQueryWrapper<CategoryEntity> categoryWrapper = new LambdaQueryWrapper<>();
        categoryWrapper.eq(CategoryEntity::getParentId,categoryVO.getId());
        categoryWrapper.orderByAsc(CategoryEntity::getSort);
        categoryWrapper.eq(CategoryEntity::getDelFlag, DelFlag.normal.getCode());
        List<CategoryEntity> selectList = categoryService.selectList(categoryWrapper);
        if (CollectionUtils.isEmpty(selectList)){
            return;
        }
        List<CategoryTreeVO> childList = new ArrayList<>();
        for (CategoryEntity categoryEntity : selectList) {
            CategoryTreeVO next = new CategoryTreeVO();
            BeanUtils.copyProperties(categoryEntity,next);
            deepLoopChildList(next);
            childList.add(next);
        }
        categoryVO.setChildList(childList);
    }
    @Override
    @ApiDoc(value = "新增类目接口")
    @Transactional(rollbackFor = Exception.class)
    public ResponseEntity<InsertCategoryVO> insert(InsertCategoryDTO dto) throws BizWrapException {
        // 1.check request
        ValidationUtils.getInstance().validate(dto);
        // 2.check name valid
        LambdaQueryWrapper<CategoryEntity> categoryWrapper = new LambdaQueryWrapper<>();
        categoryWrapper.eq(CategoryEntity::getName,dto.getName());
        categoryWrapper.eq(CategoryEntity::getDelFlag, DelFlag.normal.getCode());
        Integer selectCount = categoryService.selectCount(categoryWrapper);
        if (selectCount > 0){
            throw ExceptionWrap.wrap(GoodsCodeEnum.CATEGORY_INFO_EXIST_ERROR);
        }
        // 3.build entity
        CategoryEntity categoryEntity = new CategoryEntity();
        categoryEntity.setName(categoryEntity.getName());
        categoryEntity.setSort(categoryEntity.getSort());
        categoryEntity.setParentId(categoryEntity.getParentId());
        categoryEntity.setCreateTime(new Date());
        categoryEntity.setUpdateTime(new Date());
        categoryService.insert(categoryEntity);
        // 4.build attr
        final List<Integer> attrIdList = dto.getAttrIdList();
        if (!CollectionUtils.isEmpty(attrIdList)){
            final List<CategoryAttrEntity> categoryAttrList = new ArrayList<>();
            for (Integer attrId : attrIdList) {
                final CategoryAttrEntity categoryAttrEntity = new CategoryAttrEntity();
                categoryAttrEntity.setCategoryId(categoryEntity.getId());
                categoryAttrEntity.setAttrId(attrId);
                categoryAttrEntity.setCreateTime(new Date());
                categoryAttrList.add(categoryAttrEntity);
            }
            categoryService.batchInsertAttr(categoryAttrList);
        }
        // 4.return obj
        InsertCategoryVO insertCategoryVO = new InsertCategoryVO();
        insertCategoryVO.setId(categoryEntity.getId());
        return ResponseEntity.success(insertCategoryVO);
    }

    @Override
    @ApiDoc(value = "新增类目属性接口")
    @Transactional(rollbackFor = Exception.class)
    public ResponseEntity<Void> insertAttr(InsertCategoryAttrDTO dto) throws BizWrapException {
        // 1.check request ...
        ValidationUtils.getInstance().validate(dto);
        // 2.check category
        final CategoryEntity categoryEntity = categoryService.selectById(dto.getCategoryId());
        if (ObjectUtils.isEmpty(categoryEntity)){
            throw ExceptionWrap.wrap(GoodsCodeEnum.BRAND_INFO_NOT_EXIST_ERROR);
        }
        // 3.re-insert attr
        categoryService.deleteAttr(dto.getCategoryId());
        final List<CategoryAttrEntity> attrList = new ArrayList<>();
        dto.getAttrIdList().forEach(t->{
            final CategoryAttrEntity attrEntity = new CategoryAttrEntity();
            attrEntity.setCategoryId(categoryEntity.getId());
            attrEntity.setAttrId(t);
            attrEntity.setCreateTime(new Date());
            attrList.add(attrEntity);

        });
        categoryService.batchInsertAttr(attrList);
        return ResponseEntity.success();
    }

    @Override
    @ApiDoc(value = "修改类目接口")
    @Transactional(rollbackFor = Exception.class)
    public ResponseEntity<Void> modify(ModifyCategoryDTO dto) throws BizWrapException {
        // 1.check request
        ValidationUtils.getInstance().validate(dto);
        // 2.check name valid
        LambdaQueryWrapper<CategoryEntity> categoryWrapper = new LambdaQueryWrapper<>();
        categoryWrapper.eq(CategoryEntity::getName,dto.getName());
        categoryWrapper.ne(CategoryEntity::getId,dto.getId());
        categoryWrapper.eq(CategoryEntity::getDelFlag, DelFlag.normal.getCode());
        Integer selectCount = categoryService.selectCount(categoryWrapper);
        if (selectCount > 0){
            throw ExceptionWrap.wrap(GoodsCodeEnum.CATEGORY_NAME_EXIST_ERROR);
        }
        // 3.builder model
        CategoryEntity categoryEntity = new CategoryEntity();
        categoryEntity.setId(dto.getId());
        categoryEntity.setName(dto.getName());
        categoryEntity.setSort(dto.getSort());
        categoryEntity.setParentId(dto.getParentId());
        categoryEntity.setUpdateTime(new Date());
        categoryService.update(categoryEntity);
        // 4.return obj
        return ResponseEntity.success();
    }

    @Override
    @ApiDoc(value = "删除类目接口")
    @Transactional(rollbackFor = Exception.class)
    public ResponseEntity<Void> delete(DeleteCategoryDTO dto) throws BizWrapException {
        // 1.check request ...
        ValidationUtils.getInstance().validate(dto);
        // 2.check exist child node ...
        LambdaQueryWrapper<CategoryEntity> categoryWrapper = new LambdaQueryWrapper<>();
        categoryWrapper.eq(CategoryEntity::getParentId,dto.getId());
        categoryWrapper.eq(CategoryEntity::getDelFlag, DelFlag.normal.getCode());
        Integer selectCount = categoryService.selectCount(categoryWrapper);
        if (selectCount>0){
            throw ExceptionWrap.wrap(GoodsCodeEnum.CATEGORY_EXIST_CHILD_ERROR);
        }
        // 3.delete ...
        categoryService.delete(dto.getId());
        // 4.return obj ...
        return ResponseEntity.success();
    }
}
